/*
 * Ray.h
 *
 *  Created on: Jan 1, 2011
 *      Author: burek
 */

#ifndef RAY_H_
#define RAY_H_

#include "Vec3D.h"
#include "VecRGB.h"
#include "Vec2Di.h"

struct Ray {
    Vec3D pos;
    Vec3D dir;
    Vec2Di pixel;
    VecRGB color;
    float length;
    bool finite;
    int mode;
};

namespace RayUtils {

Ray* generateRays(Vec3D origin, Vec3D look, Vec3D up, Vec3D right, Vec2Di screen, float fov, float rayLen)
{
	Ray *rays = new Ray[screen.X * screen.Y];
	VecRGB black = VecRGB(0,0,0);
	float pixW = 0.001f;
	float pixH = 0.001f;
	float camLength = pixW * screen.X / 2.0f / tan(fov / 2.0f);

	look.NormalizeIP();
	up.NormalizeIP();
	right.NormalizeIP();

	for(int y = 0; y < screen.Y; ++y)
	{
		for(int x = 0; x < screen.X; ++x)
		{
			Vec3D Xterm = right * (pixW * (-screen.X / 2 + x + 0.5f));
			Vec3D Yterm = up * (pixH * (screen.Y / 2 - y - 0.5f));
			Vec3D Zterm = look * camLength;
			rays[y * screen.X + x].dir = Zterm + Yterm + Xterm;
			rays[y * screen.X + x].dir.NormalizeIP();
			rays[y * screen.X + x].dir *= rayLen;
			rays[y * screen.X + x].pos = origin;
			rays[y * screen.X + x].pixel.X = x;
			rays[y * screen.X + x].pixel.Y = y;
			rays[y * screen.X + x].length = 0.0f;
			rays[y * screen.X + x].color = black;
			rays[y * screen.X + x].mode = 0;
		}
	}

	return rays;
}

#define PI 3.1415926535897932384626433832795f

inline float lerp(const float x, const float y, const float a) { return x + a * (y - x); }
inline float cerp(const float x, const float y, const float a) { float a2 = (1.0f - cos(a*PI))/2.0f; return x*(1.0f-a2)+y*a2; }
inline VecRGB lerp(const VecRGB & x, const VecRGB & y, const float a)
{ return VecRGB(lerp(x.R, y.R, a), lerp(x.G, y.G, a), lerp(x.B, y.B, a)); }

}

#endif /* RAY_H_ */
